home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C++ / Applications / Nuntius 1.2 / src / Nuntius / UNewsAppl.cp < prev    next >
Encoding:
Text File  |  1994-04-13  |  30.0 KB  |  1,304 lines  |  [TEXT/MPS ]

  1. // Copyright © 1992 Peter Speck, speck@dat.ruc.dk. All rights reserved.
  2. // UNewsAppl.cp
  3.  
  4. #include "UNewsAppl.h"
  5. #include "UNewsApplCmds.h"
  6. #include "UGroupDoc.h"
  7. #include "UGroupListDoc.h"
  8. #include "UGroupTreeDoc.h"
  9. #include "UPrefsFileMgr.h"
  10. #include "UPreferencesView.h"
  11. #include "UGroupTree.h"
  12. #include "UArticleStatus.h"
  13. #include "TestCode.h"
  14. #include "UThread.h"
  15. #include "UProgressCache.h"
  16. #include "FileTools.h"
  17. #include "Tools.h"
  18. #include "UFatalError.h"
  19. #include "FontTools.h"
  20. #include "UGroupTreeCmds.h"
  21. #include "UPassword.h"
  22.  
  23. #include <RsrcGlobals.h>
  24. #include <ErrorGlobals.h>
  25.  
  26. #include <Resources.h>
  27. #include <Packages.h>
  28. #include <ToolUtils.h>
  29. #include <Fonts.h>
  30. #include <Script.h>
  31. #include <OSEvents.h>
  32.  
  33. #define qFlushVolumes 1
  34. #define qDebugPrefOpen qDebug & 0
  35. #define qDebugWindowState qDebug & 0
  36.  
  37. TNewsAppl *gNewsAppl;
  38.  
  39. const long kSaveWindowVersion = 1;
  40.  
  41. DialogPtr gSplashDiaP = nil;
  42.  
  43. #pragma segment Main
  44. void ShowSplashScreen()
  45. {
  46.     if (gSplashDiaP)
  47.         return;
  48.     if (gApplication)
  49.         gApplication->InvalidateFocus();
  50.     gSplashDiaP = GetNewDialog(phAboutBoxDlog, nil, WindowPtr(-1));
  51.     if (!gSplashDiaP)
  52.     {
  53.         if (qDebug)
  54.             ProgramBreak("Couldn't load splash screen");
  55.         return;
  56.     }
  57.     SetPort(gSplashDiaP);
  58.     BeginUpdate(gSplashDiaP);
  59.     DrawDialog(gSplashDiaP);
  60.     SetPort(gSplashDiaP);
  61.     short width = qd.thePort->portRect.right;
  62.     CStr255 s("?");
  63.     VersRecHndl vH = VersRecHndl(GetResource('vers', 1));
  64.     if (vH && *vH)
  65.         s = (*vH)->shortVersion;
  66.     s += "  ";
  67.     TextStyle ts;
  68.     MAGetTextStyle(kAboutBoxVersionTS, ts);
  69.     SetPortTextStyle(ts);
  70.     FontInfo theFontInfo;
  71.     MAGetFontInfo(theFontInfo);
  72.     MoveTo(width - StringWidth(s), theFontInfo.ascent + theFontInfo.leading);
  73.     DrawString(s);
  74.     EndUpdate(gSplashDiaP);
  75. }
  76.  
  77. void RemoveSplashScreen()
  78. {
  79.     if (gSplashDiaP)
  80.     {
  81.         FlushEvents(mDownMask | mUpMask | keyDownMask | keyUpMask | autoKeyMask, 0);
  82.         DisposeDialog(gSplashDiaP);
  83.         gSplashDiaP = nil;
  84.     }
  85. }
  86. #pragma segment MyMisc
  87. //==============================================================
  88. TNewsAppl::TNewsAppl()
  89. {
  90. }
  91.  
  92. pascal void TNewsAppl::Initialize()
  93. {
  94.     inherited::Initialize();
  95.     fWindowMenuH = nil;
  96.     fGroupListMenuH = nil;
  97.     fFontNameMenuH = nil;
  98.     fFontSizeMenuH = nil;
  99.     fLastFolderModDate = 0;
  100.     fGroupTreeDoc = nil;
  101.     fApplIsRunning = false;
  102.     fFlushVolumes = (GetResource('CMNU', mTest) != nil); // !q_Final;
  103.     fHadGroupList = false;
  104.     fLaunchWithNewDocument = false; // we don't lauch with untitled document
  105.     fIdentifier = kSignature;
  106.     fNeedCheckFolderMenus = true;
  107. }
  108.  
  109. void TNewsAppl::INewsAppl()
  110. {
  111.     inherited::IApplication('TEXT', kSignature);
  112.     FailInfo fi;
  113.     if (fi.Try())
  114.     {
  115. #if !qFlushVolumes & qDebug
  116.         fprintf(stderr, "Does NOT flush volumes!!!\n");
  117. #endif
  118.         InitUProgressCache();
  119.         InitUThread();
  120.         
  121.         CreateMenus();
  122.         RemoveSplashScreen();
  123.  
  124.         fi.Success();
  125.     }
  126.     else // fail
  127.     {
  128.         RemoveSplashScreen();
  129.         Free();
  130.         fi.ReSignal();
  131.     }
  132. }
  133.  
  134. pascal void TNewsAppl::Free()
  135. {
  136.     delete gPrefs;
  137.     inherited::Free();
  138. }
  139.  
  140. pascal void TNewsAppl::Close()
  141. {
  142. #if qDebug
  143.     fprintf(stderr, "> TNewsAppl::Close()\n");
  144. #endif
  145.     // Kill all threads except main thread
  146.     gCurThread->SetYieldDisable(false);
  147.     while (gAllThreads->GetSize() > 1)
  148.     {
  149.         TThread *thread = (TThread*)gAllThreads->Last();
  150.         thread->Kill();
  151.     }
  152.  
  153.     // save 'open windows' info 
  154.     if (gPrefs && fGroupTreeDoc)
  155.         SaveWindowState();
  156.  
  157.     WindowPtr aWMgrWindow;
  158.     // Close group + groupLists documents.  Add a block for failure handling
  159.     // start by closing the gg-document, the frontmost window belongs to
  160.     // after that, close all gg-documents
  161.     {
  162.         while ((aWMgrWindow = MAFrontWindow()) != 0)
  163.         {
  164.             TWindow *window = WMgrToWindow(aWMgrWindow);
  165.             if (!window)
  166.                 break;
  167.             TDocument *doc = window->fDocument;
  168.             if (!doc)
  169.                 break;
  170.             if (doc == fGroupTreeDoc)
  171.                 break;
  172.             doc->CloseAndFree();
  173.         }
  174.         CDocumentIterator iter(this, kIterateBackward);
  175.         for (TDocument *doc = iter.FirstDocument(); iter.More(); doc = iter.NextDocument())
  176.         {
  177.             if (doc != fGroupTreeDoc)
  178.             {
  179.                 if (doc->fWindowList && doc->fWindowList->GetSize() >= 1)
  180.                 {
  181.                     // mac centers the "save changes" dialog over frontmost window,
  182.                     // so make sure the documents main window is frontmost
  183.                     TWindow *window = (TWindow*)doc->fWindowList->First();
  184.                     window->Select();
  185.                     window->Update();
  186.                 }
  187.                 doc->CloseAndFree();
  188.             }
  189.         }
  190.     }
  191.  
  192.     // Close all of the visible non-floater windows 
  193.     while ((aWMgrWindow = MAFrontWindow()) != 0)
  194.         this->CloseToolboxWindow(aWMgrWindow);
  195.  
  196.     // Close all of the windows 
  197.     while ((aWMgrWindow = FrontWindow()) != 0)
  198.         this->CloseToolboxWindow(aWMgrWindow);
  199.  
  200.     // some of the managers may
  201.     //   have cohandlers,
  202.     //   need TPrefsDoc
  203.     // so close them before closing
  204.     //   the cohandler chain
  205.     //   the preferences
  206.     CloseDownTheManagers();
  207.     
  208.  
  209.     // Close any windowless documents.  Add a block for failure handling
  210.     {
  211.         CDocumentIterator iter(this);
  212.  
  213.         for (TDocument * aDocument = iter.FirstDocument(); iter.More(); aDocument = iter.NextDocument())
  214.             aDocument->CloseAndFree();
  215.     }
  216.  
  217.     // Close down the cohandler chain.  Add a block for failure handling
  218.     {
  219.         CHandlerIterator iter(fHeadCohandler);
  220.         for (TEventHandler *aHandler = iter.FirstHandler(); iter.More(); aHandler = iter.NextHandler())
  221.             FreeIfObject(aHandler);                // ??? also call Terminate ??? 
  222.     }
  223.  
  224.     if (gPrefsFileMgr)
  225.         gPrefsFileMgr->Save();
  226. #if qDebug
  227.     fprintf(stderr, "< TNewsAppl::Close()\n");
  228. #endif
  229.     inherited::Close(); // does not free
  230. }
  231.  
  232. void TNewsAppl::SaveWindowState()
  233. {
  234. #if qDebugWindowState
  235.     fprintf(stderr, "Saves Window State\n");
  236. #endif
  237.     Handle h = nil;
  238.     VOLATILE(h);
  239.     THandleStream *aStream = nil;
  240.     VOLATILE(aStream);
  241.     FailInfo fi;
  242.     if (fi.Try())
  243.     {
  244.         h = NewPermHandle(0);
  245.         THandleStream *hs = new THandleStream();
  246.         hs->IHandleStream(h, 128);
  247.         aStream = hs; hs = nil;
  248.         
  249.         aStream->WriteLong(kSaveWindowVersion);
  250.         aStream->WriteLong('TInf');
  251.         fGroupTreeDoc->WriteTreeInfo(aStream);
  252.         if (gPrefs->GetBooleanPrefs('WSav'))
  253.             DoSaveWindowStates(aStream);
  254.         aStream->WriteLong('Slut');
  255.         
  256.         FreeIfObject(aStream); aStream = nil;
  257.         gPrefs->SetHandlePrefs('Wind', h);
  258.         h = DisposeIfHandle(h);
  259.         fi.Success();
  260.     }
  261.     else // fail
  262.     {
  263.         FreeIfObject(aStream); aStream = nil;
  264.         h = DisposeIfHandle(h);
  265.         // no resignal as we're quitting
  266.     }
  267. }
  268.  
  269. void TNewsAppl::DoSaveWindowStates(TStream *aStream)
  270. {
  271.     CWMgrIterator iter(kIterateBackward);
  272.     for (WindowPtr windP = iter.FirstWMgrWindow(); iter.More(); windP = iter.NextWMgrWindow())
  273.     {
  274.         TWindow *window = WMgrToWindow(windP);
  275.         if (!window || !window->fDocument)
  276.             continue;
  277.         OSType id = window->fDocument->fIdentifier;
  278. #if qDebugWindowState
  279.         fprintf(stderr, "Writes type id = $%lx, position = %ld\n", id, aStream->GetPosition() + 4);
  280.         fprintf(stderr, "Got window with id = $%lx\n", id);
  281. #endif
  282.         if (id == kGroupTreeDocFileType)
  283.         {
  284. #if qDebugWindowState
  285.             fprintf(stderr, "Writes TWin\n");
  286. #endif
  287.             aStream->WriteLong('TWin');
  288.             fGroupTreeDoc->WriteWindowInfo(aStream, window);
  289.         }
  290.         else if (id == kGroupListDocFileType)
  291.         {
  292. #if qDebugWindowState
  293.             fprintf(stderr, "Writes GLis\n");
  294. #endif
  295.             aStream->WriteLong('GLis');
  296.             AliasHandle ah = ( (TGroupListDoc*) window->fDocument)->GetAlias();
  297.             aStream->WriteHandle(Handle(ah));
  298.             DisposeIfHandle(Handle(ah)); ah = nil;
  299.         }
  300.     }
  301. }
  302.  
  303. void TNewsAppl::RestoreWindowState()
  304. {
  305.     if (!gPrefs->PrefExists('Wind') || gPrefs->GetPrefsSize('Wind') <= 4)
  306.         return; // got no info
  307. #if qDebugWindowState
  308.     fprintf(stderr, "Restores Window State\n");
  309. #endif
  310.     Handle h = gPrefs->GetHandlePrefs('Wind');
  311.     VOLATILE(h);
  312.     THandleStream *aStream = nil;
  313.     VOLATILE(aStream);
  314.     FailInfo fi;
  315.     if (fi.Try())
  316.     {
  317.         THandleStream *hs = new THandleStream();
  318.         hs->IHandleStream(h, 128);
  319.         aStream = hs; hs = nil;
  320.         if (aStream->ReadLong() != kSaveWindowVersion)
  321.             Failure(0 ,0);
  322.         while (true)
  323.         {
  324.             long id = aStream->ReadLong();
  325. #if qDebugWindowState
  326.             fprintf(stderr, "Restore type id = $%lx, position = %ld\n", id, aStream->GetPosition());
  327. #endif
  328.             if (id == 'Slut')
  329.                 break;
  330.             else if (id == 'TInf')
  331.                 fGroupTreeDoc->ReadTreeInfo(aStream);
  332.             else if (id == 'TWin')
  333.                 fGroupTreeDoc->ReadWindowInfo(aStream);
  334.             else if (id == 'GLis')
  335.             {
  336.                 AliasHandle ah = AliasHandle(aStream->ReadHandle());
  337.                 TFile *file = DoMakeFile(cNewGroupListDoc);
  338.                 if (file->SpecifyWithAlias(ah) == noErr)
  339.                 {
  340.                     FailInfo fi2;
  341.                     if (fi2.Try())
  342.                     {
  343.                         OpenOneOld(file);
  344.                         fi2.Success();
  345.                     }
  346.                 }
  347.                 DisposeIfHandle(Handle(ah)); ah = nil;
  348.             }
  349.             else
  350.                 break; // unknown type
  351.         } // while
  352.         FreeIfObject(aStream); aStream = nil;
  353.         h = DisposeIfHandle(h);
  354.         fi.Success();
  355.     }
  356.     else // fail
  357.     {
  358.         FreeIfObject(aStream); aStream = nil;
  359.         h = DisposeIfHandle(h);
  360.         // no resignal, just ignore error
  361.     }
  362. }
  363.  
  364. void TNewsAppl::SetGroupTreeDoc(TGroupTreeDoc *doc)
  365. {
  366. #if qDebug
  367.     if (fGroupTreeDoc)
  368.         ProgramBreak("has fGroupTreeDoc");
  369. #endif
  370.     fGroupTreeDoc = doc;
  371. }
  372.  
  373. TGroupTreeDoc *TNewsAppl::GetGroupTreeDoc()
  374. {
  375. #if qDebug
  376.     if (!fGroupTreeDoc)
  377.         ProgramBreak("Called before fGroupTreeDoc is set");
  378. #endif
  379.     return fGroupTreeDoc;
  380. }
  381.  
  382. TGroupTree *TNewsAppl::GetGroupTree()
  383. {
  384. #if qDebug
  385.     if (!fGroupTreeDoc)
  386.         ProgramBreak("Called before fGroupTreeDoc is set");
  387. #endif
  388.     return fGroupTreeDoc->GetGroupTree();
  389. }
  390.  
  391. void TNewsAppl::QuickUpdateGroupHasNoNewArticles(const CStr255 &dotName)
  392. {
  393.     CDocumentIterator iter(this);
  394.     for (TDocument *doc = iter.FirstDocument(); iter.More(); doc = iter.NextDocument())
  395.     {
  396.         if (doc->fIdentifier != kGroupListDocFileType)
  397.             continue;
  398.         TGroupListDoc *gld = (TGroupListDoc*)doc;
  399.         gld->UpdateGroupStatus(dotName, false);
  400.     }
  401. }
  402.  
  403. pascal void TNewsAppl::DoAboutBox()
  404. {
  405.     FailSpaceIsLow();
  406.     FlushEvents(mDownMask | mUpMask | keyDownMask | keyUpMask | autoKeyMask, 0);
  407.     ShowSplashScreen();
  408.     EventRecord event;
  409.     while (!Button() && !EventAvail(mDownMask | keyDownMask, event))
  410.         UpdateAllWindows();
  411.     RemoveSplashScreen();
  412. }
  413.  
  414.  
  415. pascal void TNewsAppl::GetHelpParameters(ResNumber helpResource,
  416.                                                         short helpIndex, short helpState,
  417.                                                         HMMessageRecord &helpMessage,
  418.                                                         CPoint &localQDTip, CRect &localQDRect, short &balloonVariant)
  419. {
  420.     // all of this is needed as the HelpMgr calls Get1Resource (and I have multiple rsrc files)
  421.     short oldRefNum = CurResFile();
  422.     VOLATILE(oldRefNum);
  423.     FailInfo fi;
  424.     if (fi.Try())
  425.     {
  426.         Handle h = GetResource(kHMDialogResType, helpResource);
  427.         if (h)
  428.             UseResFile(HomeResFile(h));
  429.         inherited::GetHelpParameters(helpResource, helpIndex, helpState, helpMessage, localQDTip, localQDRect, balloonVariant);
  430.         UseResFile(oldRefNum);
  431.         fi.Success();
  432.     }
  433.     else // fail
  434.     {
  435.         UseResFile(oldRefNum);
  436.         fi.ReSignal();
  437.     }
  438. }
  439.  
  440. pascal void TNewsAppl::DoAppleCommand(CommandNumber aCommandNumber, const AppleEvent& message, const AppleEvent& reply)
  441. {
  442.     if (!gPrefs && aCommandNumber == cFinderNew)
  443.     {
  444. #if qDebugPrefOpen
  445.     fprintf(stderr, "Got cFinderOpen and !gPrefs in DoAppleCommand, opens default prefs\n");
  446. #endif
  447.         // open prefs in preferences folder
  448.         TOpenPrefsCommand *cmd = new TOpenPrefsCommand();
  449.         cmd->IOpenPrefsCommand();
  450.         gApplWideThreads->ExecuteCommand(cmd, "TOpenPrefsCommand without files (cFinderNew)");
  451.     }
  452.     inherited::DoAppleCommand(aCommandNumber, message, reply);
  453. }
  454.  
  455. pascal void TNewsAppl::OpenOld(CommandNumber itsOpenCommand, TList* aFileList)
  456. {
  457.     if (gPrefs)
  458.     {
  459.         inherited::OpenOld(itsOpenCommand, aFileList);
  460.         return;
  461.     }
  462. #if qDebugPrefOpen
  463.     fprintf(stderr, "Got OpenOld with !gPrefs\n");
  464. #endif
  465.     TList *docList = nil;
  466.     VOLATILE(docList);
  467.     FailInfo fi;
  468.     if (fi.Try())
  469.     {
  470.         docList = NewList();
  471.         CopyDynamicArray(aFileList, docList);
  472.         aFileList->DeleteAll();
  473. #if qDebugPrefOpen
  474.         fprintf(stderr, "Executes open prefs command with %ld doc files\n", docList->GetSize());
  475. #endif
  476.         TOpenPrefsCommand *cmd = new TOpenPrefsCommand();
  477.         cmd->IOpenPrefsCommand(docList);
  478.         docList = nil;
  479.         gApplWideThreads->ExecuteCommand(cmd, "TOpenPrefsCommand with files (OpenOld)");
  480.         fi.Success();
  481.     }
  482.     else // fail: could not open prefs file
  483.     {
  484. #if qDebugPrefOpen
  485.         fprintf(stderr, "Could not make open_prefs_file command, quits\n");
  486. #endif
  487.         DoMenuCommand(cQuit);
  488.         FreeIfObject(docList); docList = nil;
  489.         fi.ReSignal();
  490.     }
  491. }
  492.  
  493. pascal CommandNumber TNewsAppl::KindOfDocument(CommandNumber itsCommandNumber, TFile* itsFile)
  494. {
  495.     if (itsFile)
  496.     {
  497.         switch (itsFile->fFileType)
  498.         {
  499.             case kGroupTreeDocFileType:
  500.                 return cNewGroupTreeDoc;
  501.  
  502.             case kGroupDBFileType:
  503.             case kArticleStatusFileType:
  504.                 FailOSErr(errNotImplemented);
  505.  
  506.             case kGroupListDocFileType:
  507.                 return cNewGroupListDoc;
  508.             
  509.             default:
  510.                 break;
  511.         }
  512.     }
  513.     switch (itsCommandNumber)
  514.     {
  515.         case cNewGroupListDoc:
  516.         case cOpenGroupListDoc:
  517.             return cNewGroupListDoc;
  518.  
  519.         case cNewGroupTreeDoc:
  520.         case cOpenGroupTreeDoc:
  521.             return cNewGroupTreeDoc;
  522.         
  523.         default:
  524.             return inherited::KindOfDocument(itsCommandNumber, itsFile);
  525.     }
  526. }
  527.  
  528. pascal TDocument *TNewsAppl::DoMakeDocument(CommandNumber itsCommandNumber, TFile *itsFile)
  529. {
  530.     switch (itsCommandNumber)
  531.     {
  532.         case cNewGroupTreeDoc:
  533.             if (!fGroupTreeDoc)
  534.             {
  535.                 TGroupTreeDoc *gtd = new TGroupTreeDoc();
  536.                 gtd->IGroupTreeDoc(itsFile);
  537.                 return gtd;
  538.             }
  539.             else 
  540.                 FailOSErr(errNotImplemented);
  541.             
  542.         case cNewGroupListDoc:
  543.             gBusyCursor->ForceBusy();
  544.             {
  545.                 TGroupListDoc *gld = new TGroupListDoc();
  546.                 gld->IGroupListDoc(itsFile);
  547.                 return gld;
  548.             }
  549.  
  550.         default:
  551.             FailOSErr(errNotMyType);
  552.             return nil;
  553.     }
  554. }
  555.  
  556. pascal TFile* TNewsAppl::DoMakeFile(CommandNumber itsCommandNumber)
  557. {
  558.     TFile *file = nil;
  559.     VOLATILE(file);
  560.     FailInfo fi;
  561.     if (fi.Try())
  562.     {
  563.         switch (itsCommandNumber)
  564.         {
  565.             case cOpen:
  566.             case cFinderOpen:
  567.             case cSave:
  568.             case cSaveAs:
  569.                 //@@ not sure here, does the caller always change fileType etc..
  570.                 file = NewFile('????', fCreator, !kUsesDataFork, preferResourceFork, !kDataOpen, !kRsrcOpen);
  571.                 break;
  572.  
  573.             case cNewGroupListDoc:
  574.                 file = NewFile(kGroupListDocFileType, kSignature, kUsesDataFork, preferResourceFork, kDataOpen, kRsrcOpen);
  575.                 GoPrefsLocation(file, kUntitledFileName);
  576.                 break;
  577.                 
  578.             case cNewGroupTreeDoc:
  579.                 file = NewFile(kGroupTreeDocFileType, kSignature, kUsesDataFork, preferResourceFork, kDataOpen, kRsrcOpen);
  580.                 GoPrefsLocation(file, kGroupTreeFileName);
  581.                 break;
  582.                 
  583.             default:
  584.                 FailOSErr(errNotMyType);
  585.         }
  586.         fi.Success();
  587.         return file;
  588.     }
  589.     else // fail
  590.     {
  591.         FreeIfObject(file); file = nil;
  592.         fi.ReSignal();
  593.     }
  594. }
  595.  
  596. pascal void TNewsAppl::GetFileTypeList(CommandNumber, TypeListHandle& typeList)
  597. {
  598.     typeList = TypeListHandle(NewPermHandle(4));
  599.     if (!gPrefs)
  600.     {
  601.         // if we are not up and running, only prefs file can be opened
  602.         (*typeList)[0] = kPrefsFileType;
  603.     }
  604.     else if (!fGroupTreeDoc)
  605.     {
  606.         (*typeList)[0] = kGroupTreeDocFileType;
  607.     }
  608.     else
  609.     {
  610.         (*typeList)[0] = kGroupListDocFileType;
  611.     }
  612. }
  613.  
  614. pascal Boolean TNewsAppl::CanOpenDocument(CommandNumber itsCommandNumber, TFile* aFile)
  615. {
  616.     if (!gPrefs)
  617.         return (aFile->fFileType == kPrefsFileType);
  618.     if (!fGroupTreeDoc)
  619.         return (aFile->fFileType == kGroupTreeDocFileType);
  620.     switch (aFile->fFileType)
  621.     {
  622.         case kGroupDBFileType:
  623.         case kArticleStatusFileType:
  624.             FailOSErr(errNotImplemented);
  625.  
  626.         case kPrefsFileType:
  627.         case kGroupTreeDocFileType:
  628.             FailOSErr(errNotImplemented);
  629.  
  630.         case kGroupListDocFileType:
  631.             return true;
  632.             
  633.         default:
  634.             return inherited::CanOpenDocument(itsCommandNumber, aFile);
  635.     }
  636. }
  637.  
  638. void TNewsAppl::OpenOneOld(TFile *file)
  639. {
  640.     VOLATILE(file);
  641.     TList *list = nil;
  642.     VOLATILE(list);
  643.     FailInfo fi;
  644.     if (fi.Try())
  645.     {
  646.         list = NewList();
  647.         list->InsertLast(file); file = nil;
  648.         OpenOld(cOpen, list);
  649.         FreeIfObject(list); list = nil;
  650.         fi.Success();
  651.     }
  652.     else // fail
  653.     {
  654.         FreeIfObject(file); file = nil;
  655.         if (list)
  656.         {
  657.             list->DeleteAll();
  658.             FreeIfObject(list); list = nil;
  659.         }
  660.         fi.ReSignal();
  661.     }
  662. }
  663.  
  664. pascal void TNewsAppl::DoToolboxEvent(TToolboxEvent* event)
  665. {
  666.     // avoid to yield while updating windows as CSubViewIterator has
  667.     // links in the stack
  668.     Boolean wasDisabled = gCurThread->SetYieldDisable(true);
  669.     VOLATILE(wasDisabled);
  670.     FailInfo fi;
  671.     if (fi.Try())
  672.     {
  673.         inherited::DoToolboxEvent(event);
  674.         gCurThread->SetYieldDisable(wasDisabled);
  675.         fi.Success();
  676.     }
  677.     else // fail
  678.     {
  679.         gCurThread->SetYieldDisable(wasDisabled);
  680.         fi.ReSignal();
  681.     }
  682. }
  683.  
  684. pascal void TNewsAppl::SpaceIsLowAlert()
  685. {
  686.     if (GetNumThreads() <= 1)
  687.     {
  688.         inherited::SpaceIsLowAlert();
  689.         return;
  690.     }
  691.     // Show 'space is low' alert only after ever fLowSpaceInterval ticks. 
  692.     if ((fLowSpaceInterval > 0) && this->IsFrontProcess())
  693.     {
  694.         long now = TickCount();
  695.         if (now > fNextSpaceMessage)
  696.         {
  697.             gInhibitNestedHandling = TRUE;        // Don't tell em again from the alert 
  698.             StdAlert(phMySpaceIsLow);
  699.             fNextSpaceMessage = now + fLowSpaceInterval;
  700.         }
  701.     }
  702. }
  703.  
  704. pascal void TNewsAppl::UpdateAllWindows()
  705. {
  706.     TToolboxEvent * event;
  707.  
  708.     ++fEventLevel;
  709.     short iters = 0;
  710.     while (event = this->GetEvent(updateMask + activMask, 0, NULL))
  711.     {
  712.         event->Process();
  713.         if (++iters > 2)
  714.             break;
  715.     }
  716.     --fEventLevel;
  717. }
  718.  
  719. pascal TToolboxEvent *TNewsAppl::GetEvent(short eventMask, long sleep, RgnHandle sleepRegion)
  720. {
  721.     if (GetNumThreads() > 1)
  722.     {
  723.         Boolean wasDisabled = gCurThread->SetYieldDisable(false);
  724.         gCurThread->YieldTime();
  725.         gCurThread->SetYieldDisable(wasDisabled);
  726.         if (IsFrontProcess())
  727.             sleep = 0;
  728.         else
  729.             sleep = Min(6, sleep); // be a bit gently when in background
  730.     }
  731.     if (fFlushVolumes)
  732.         FlushVols();
  733.     return inherited::GetEvent(eventMask, sleep, sleepRegion);
  734. }
  735.  
  736. pascal void TNewsAppl::DoKeyEvent(TToolboxEvent *event)
  737. {
  738.     switch (event->fCharacter)
  739.     {
  740.         case 19: // ctrl-s
  741.             {
  742.                 CDocumentIterator iter(this);
  743.                 for (TDocument *doc = iter.FirstDocument(); iter.More(); doc = iter.NextDocument())
  744.                 {
  745.                     if (doc->GetChangeCount() > 0)
  746.                         doc->SaveDocument(cSave);
  747.                 }
  748.                 FlushVols();
  749.             }
  750.             break;
  751.                 
  752.         default:
  753.             inherited::DoKeyEvent(event);
  754.             break;
  755.     }
  756. }
  757.  
  758. //========================== M E N U S ====================================
  759. Boolean TNewsAppl::HandleFontMenu(CommandNumber cmd, TextStyle &ts)
  760. {
  761.     if (cmd >= 0)
  762.         return false;
  763.     short menu, item;
  764.     CommandToMenuItem(cmd, menu, item);
  765.     CStr255 s;
  766.     if (menu == mFontSize)
  767.     {
  768.         GetItem(fFontSizeMenuH, item, s);
  769.         long size;
  770.         StringToNum(s, size);
  771.         if (ts.tsSize == size)
  772.             return false;
  773.         ts.tsSize = short(size);
  774.         return true;
  775.     }
  776.     else if (menu == mFontName)
  777.     {
  778.         GetItem(fFontNameMenuH, item, s);
  779.         short num;
  780.         GetFNum(s, num);
  781.         if (num == ts.tsFont)
  782.             return false;
  783.         ts.tsFont = num;
  784.         return true;
  785.     }
  786.     else
  787.         return false;
  788. }                    
  789.  
  790. void TNewsAppl::CreateMenus()
  791. {
  792. // Group lists
  793.     fGroupListMenuH = MAGetMenu(mGroupLists); // GetMHandle
  794.     FailNIL(fGroupListMenuH);
  795.  
  796. // Window
  797.     fWindowMenuH = MAGetMenu(mWindows);
  798.     FailNIL(fWindowMenuH);
  799.  
  800. // Font size
  801.     fFontSizeMenuH = MAGetMenu(mFontSize);
  802.     FailNIL(fFontSizeMenuH);
  803.  
  804. // Font names
  805.     fFontNameMenuH = MAGetMenu(mFontName);
  806.     FailNIL(fFontNameMenuH);
  807.     AddResMenu(fFontNameMenuH, 'FONT');
  808.     NeedCalcMenuSize(fFontNameMenuH);
  809. }
  810.  
  811. void TNewsAppl::EnableFontMenu(TextStyle ts)
  812. {
  813. // size
  814.     short item = CountMItems(fFontSizeMenuH);
  815.     CStr255 s, currSel;
  816.     NumToString(ts.tsSize, currSel);
  817.     while (item >= 1)
  818.     {
  819.         GetItem(fFontSizeMenuH, item, s);
  820.         CheckItem(fFontSizeMenuH, item, s == currSel);
  821.         item--;
  822.     }
  823.     (*fFontSizeMenuH)->enableFlags = 0xFFFFFFFF;
  824. // names
  825.     GetFontName(ts.tsFont, currSel);
  826.     item = CountMItems(fFontNameMenuH);
  827.     while (item >= 1)
  828.     {
  829.         GetItem(fFontNameMenuH, item, s);
  830.         CheckItem(fFontNameMenuH, item, s == currSel);
  831.         item--;
  832.     }
  833.     (*fFontNameMenuH)->enableFlags = 0xFFFFFFFF;
  834. }
  835.  
  836. void TNewsAppl::DoWindowsMenu(short itemToSelect)
  837. {
  838.     (*fWindowMenuH)->enableFlags = 0;
  839.     short itemNo = CountMItems(fWindowMenuH);
  840.     for (;itemNo; itemNo--)
  841.         DelMenuItem(fWindowMenuH, itemNo);
  842.     GrafPtr savePort;
  843.     GetPort(savePort);
  844.     SetPort(gWorkPort);
  845.     SetPortTextStyle(gSystemStyle);
  846.     Boolean isModal = true;
  847.     WindowPtr fw = MAFrontWindow();
  848.     if (fw)
  849.     {
  850.         TWindow *wind = WMgrToWindow(fw);
  851.         if (wind)
  852.             isModal = wind->IsInModalState();
  853.     }
  854.  
  855.     Boolean gotADocument = false;
  856.     Boolean multipleDocuments = (fDocumentList->fSize > 1);
  857.     CDocumentIterator docIter(this);
  858.     for (TDocument *doc = docIter.FirstDocument(); docIter.More(); doc = docIter.NextDocument())
  859.     {
  860. #if qDebug
  861.         if (!IsObject(doc))
  862.         {
  863.             fprintf(stderr, "doc = $%lx is not object\n", long(doc));
  864.             ProgramBreak(gEmptyString);
  865.             continue;
  866.         }
  867. #endif
  868.         Boolean firstDocWindow = true;
  869.         CWindowIterator windIter(doc);
  870.         for (TWindow *wind = windIter.FirstWindow(); windIter.More(); wind = windIter.NextWindow())
  871.         {
  872. #if qDebug
  873.             if (!IsObject(wind))
  874.                 ProgramBreak("wind is not object");
  875. #endif
  876. //            if (wind->IsShown() && !wind->fFloats)
  877.             if (wind->IsShown())
  878.             {
  879.                 CStr255 title;
  880.                 if (firstDocWindow)
  881.                 {
  882.                     if (gotADocument)
  883.                     {
  884.                         AppendMenu(fWindowMenuH, "-");
  885.                         itemNo++;
  886.                     }
  887. #if 0
  888.                     if (multipleDocuments)
  889.                     {
  890.                         AppendMenu(fWindowMenuH, "z"); 
  891.                         itemNo++;
  892.                         title = doc->fTitle;
  893.                         if (title == "")
  894.                             title = "?";
  895.                         SetItem(fWindowMenuH, itemNo, title);
  896.                     }
  897. #endif
  898.                 }
  899.                 WindowPtr windP = wind->GetGrafPort();
  900.                 GetWTitle(windP, title);
  901.                 TruncSystemFontString(300, title, smTruncMiddle);
  902. #if 1
  903.                 if (firstDocWindow == false)
  904.                     title.Insert("   ", 1);
  905. #else
  906.                 if (multipleDocuments)
  907.                     title.Insert("   ", 1);
  908. #endif
  909.                 if (wind->fFloats)
  910.                     title.Insert(" ", 1);
  911.                 if (title.Length() == 0)
  912.                     continue;
  913.                 AppendMenu(fWindowMenuH, "z"); 
  914.                 itemNo++;
  915.                 SetItem(fWindowMenuH, itemNo, title);
  916.                 if (itemNo == itemToSelect)
  917.                 {
  918.                     InvalidateFocus();
  919.                     wind->Select();
  920.                 }
  921.                 if (!isModal)
  922.                     EnableItem(fWindowMenuH, itemNo);
  923.                 if (windP == fw)
  924.                     CheckItem(fWindowMenuH, itemNo, true);
  925.                 firstDocWindow = false;
  926.                 gotADocument = true;
  927.             }
  928.         }
  929.     }
  930.     Boolean firstWindow = true;
  931.     CObjectIterator objIter(fFreeWindowList);
  932.     for (TObject *obj = objIter.FirstObject(); objIter.More(); obj = objIter.NextObject())
  933.     {
  934.         TWindow *wind = (TWindow*)obj;
  935. #if qDebug
  936.             if (!IsObject(wind))
  937.                 ProgramBreak("wind is not object");
  938. #endif
  939. //        if (wind->IsShown() && !wind->fFloats)
  940.         if (wind->IsShown())
  941.         {
  942.             if (gotADocument && firstWindow)
  943.             {
  944.                 AppendMenu(fWindowMenuH, "-");
  945.                 itemNo++;
  946.             }
  947.             WindowPtr windP = wind->GetGrafPort();
  948.             CStr255 title;
  949.             GetWTitle(windP, title);
  950.             TruncSystemFontString(300, title, smTruncMiddle);
  951.             AppendMenu(fWindowMenuH, "z"); 
  952.             itemNo++;
  953.             if (itemNo == itemToSelect)
  954.             {
  955.                 InvalidateFocus();
  956.                 wind->Select();
  957.                 return;
  958.             }
  959.             SetItem(fWindowMenuH, itemNo, title);
  960.             if (!isModal)
  961.                 EnableItem(fWindowMenuH, itemNo);
  962.             if (windP == fw)
  963.                 CheckItem(fWindowMenuH, itemNo, true);
  964.             firstWindow = false;
  965.         }
  966.     }
  967.     SetPort(savePort);
  968.     NeedCalcMenuSize(fWindowMenuH);
  969. }
  970.  
  971. void TNewsAppl::UpdateGroupListMenu()
  972. {
  973.     if (fHadGroupList)
  974.         (*fGroupListMenuH)->enableFlags = 0x7FFFFFFF;
  975.     if (fNeedCheckFolderMenus == false)
  976.         return;
  977.     CStr255 name;
  978.     FSSpec spec;
  979.     GetPrefsDocLocation(spec);
  980.     CInfoPBRec pbc;
  981.     pbc.dirInfo.ioFDirIndex = -1;
  982.     pbc.dirInfo.ioNamePtr = (StringPtr)name;
  983.     pbc.dirInfo.ioVRefNum = spec.vRefNum;
  984.     pbc.dirInfo.ioDrDirID = spec.parID;
  985.     if (PBGetCatInfoSync(&pbc) != noErr)
  986.         return;
  987.     if (pbc.dirInfo.ioDrMdDat == fLastFolderModDate)
  988.         return;
  989. #if qDebug
  990.     fprintf(stderr, "Updates group list menu\n");
  991. #endif
  992.     fLastFolderModDate = pbc.dirInfo.ioDrMdDat;
  993.     short noItems = CountMItems(fGroupListMenuH);
  994.     while (noItems)
  995.         DelMenuItem(fGroupListMenuH, noItems--);
  996.     HParamBlockRec pbf;
  997.     pbf.fileParam.ioFDirIndex = 1;
  998.     while (true)
  999.     {
  1000.         pbf.fileParam.ioVRefNum = spec.vRefNum;
  1001.         pbf.fileParam.ioDirID = spec.parID;
  1002.         pbf.fileParam.ioNamePtr = (StringPtr)name;
  1003.         pbf.fileParam.ioFVersNum = 0;
  1004.         if (PBHGetFInfoSync(&pbf) != noErr)
  1005.             break;
  1006.         pbf.fileParam.ioFDirIndex++;
  1007.         if (pbf.fileParam.ioFlFndrInfo.fdType != kGroupListDocFileType)
  1008.             continue;
  1009.  
  1010.         noItems++;
  1011.         AppendMenu(fGroupListMenuH, "hi there"); // may not be empty
  1012.         SetItem(fGroupListMenuH, noItems, name);
  1013.         if (noItems <= 9)
  1014.             SetItemCmd(fGroupListMenuH, noItems, '0' + noItems);
  1015.         fHadGroupList = true;
  1016.     }
  1017.     if (noItems)
  1018.         (*fGroupListMenuH)->enableFlags = 0x7FFFFFFF;
  1019.     else
  1020.     {
  1021.         MyGetIndString(name, kEmptyGroupListMenuText);
  1022.         AppendMenu(fGroupListMenuH, "hi there"); // may not be empty
  1023.         SetItem(fGroupListMenuH, 1, name);
  1024.         (*fGroupListMenuH)->enableFlags = 0;
  1025.     }
  1026.     NeedCalcMenuSize(fGroupListMenuH);
  1027.     fNeedCheckFolderMenus = false;
  1028. }
  1029.  
  1030. pascal void TNewsAppl::RegainControl(Boolean checkClipboard)
  1031. {
  1032.     SetNeedCheckFolderMenus();
  1033.     inherited::RegainControl(checkClipboard);
  1034. }
  1035.  
  1036. void TNewsAppl::SetNeedCheckFolderMenus()
  1037. {
  1038.     fNeedCheckFolderMenus = true;
  1039. }
  1040.  
  1041. void TNewsAppl::HandleGroupListMenu(short item)
  1042. {
  1043.     FailInfo fi;
  1044.     if (fi.Try())
  1045.     {
  1046.         CStr255 name;
  1047.         GetItem(fGroupListMenuH, item, name);
  1048.     
  1049.         TFile *file = gNewsAppl->DoMakeFile(cNewGroupListDoc);
  1050.         file->SetName(name);
  1051.         ResolveAliasFile(file);
  1052.         gNewsAppl->OpenOneOld(file);
  1053.         fi.Success();
  1054.     }
  1055.     else // fail
  1056.         FailNewMessage(fi.error, fi.message, messageOpenGroupFailed);
  1057. }
  1058. //---------------------
  1059. pascal void TNewsAppl::DoMenuCommand(CommandNumber aCommandNumber)
  1060. {
  1061.     TWindow *aWindow;            
  1062.     if (aCommandNumber < 0)
  1063.     {
  1064.         short menu, itemNo;
  1065.         CommandToMenuItem(aCommandNumber, menu, itemNo);
  1066.         if (menu == mWindows)
  1067.         {
  1068.             DoWindowsMenu(itemNo);
  1069.             return;
  1070.         }
  1071.         else if (menu == mGroupLists)
  1072.         {
  1073.             HandleGroupListMenu(itemNo);
  1074.             return;
  1075.         }
  1076.     }
  1077.     switch (aCommandNumber)
  1078.     {
  1079.         case cQuit:
  1080.             SetupTheMenus();
  1081.             if (CommandEnabled(cQuit))
  1082.                 inherited::DoMenuCommand(cQuit);
  1083.             break;
  1084.             
  1085.         case cOpenListOfAllGroups:
  1086.             fGroupTreeDoc->CreateGroupTreeWindow();
  1087.             break;
  1088.         
  1089. //-----
  1090.  
  1091.         case cPrefShowAllArticles:
  1092.             gPrefs->SetShortPrefs('artS', kShowAllArticles);
  1093.             break;
  1094.  
  1095.         case cPrefShowOnlyFirstArticle:
  1096.             gPrefs->SetShortPrefs('artS', kShowFirstArticleOnly);
  1097.             break;
  1098.  
  1099.         case cPrefShowOnlyUnreadArticles:
  1100.             gPrefs->SetShortPrefs('artS', kShowUnreadArticles);
  1101.             break;
  1102.  
  1103.         case cPrefShowOnlyNewArticles:
  1104.             gPrefs->SetShortPrefs('artS', kShowNewArticles);
  1105.             break;
  1106.  
  1107.         case cPrefShowNoneArticles:
  1108.             gPrefs->SetShortPrefs('artS', kShowNoArticles);
  1109.             break;
  1110.  
  1111. //-----
  1112.  
  1113.         case cPrefShowAllDiscussions:
  1114.             gPrefs->SetShortPrefs('disS', kShowAllDiscs);
  1115.             break;
  1116.  
  1117.         case cPrefShowOnlyTodayDiscussions:
  1118.             gPrefs->SetShortPrefs('disS', kShowTodaysDiscs);
  1119.             break;
  1120.  
  1121.         case cPrefShowDiscsWithUnreadArticles:
  1122.             gPrefs->SetShortPrefs('disS', kShowDiscsWithUnreadArticles);
  1123.             break;
  1124.  
  1125.         case cPrefShowDiscsWithNewArticles:
  1126.             gPrefs->SetShortPrefs('disS', kShowDiscsWithNewArticles);
  1127.             break;
  1128.  
  1129. //-----
  1130.  
  1131.         case cUpdateGroupTree:
  1132.             {
  1133.                 TUpdateListOfAllGroupsCommand *cmd = new TUpdateListOfAllGroupsCommand();
  1134.                 cmd->IUpdateListOfAllGroupsCommand(fGroupTreeDoc, false);
  1135.                 gApplWideThreads->ExecuteCommand(cmd, "TUpdateListOfAllGroupsCommand (update)");
  1136.             }
  1137.             break;
  1138.         
  1139.         case cRebuildGroupTree:
  1140.             {
  1141.                 TUpdateListOfAllGroupsCommand *cmd = new TUpdateListOfAllGroupsCommand();
  1142.                 cmd->IUpdateListOfAllGroupsCommand(fGroupTreeDoc, true);
  1143.                 gApplWideThreads->ExecuteCommand(cmd, "TUpdateListOfAllGroupsCommand (rebuild)");
  1144.             }
  1145.             break;
  1146.         
  1147.         case cOpenYourNamePrefs:
  1148.             DoYourNamePreferencesDialog();
  1149.             break;
  1150.             
  1151.         case cOpenNewsServerPrefs:
  1152.             DoNewsServerPreferencesDialog();
  1153.             break;
  1154.  
  1155.         case cOpenBinariesPrefs:
  1156.             DoBinariesPreferencesDialog();
  1157.             break;
  1158.  
  1159.         case cOpenEditorPrefs:
  1160.             DoEditorPreferencesDialog();
  1161.             break;
  1162.         
  1163.         case cOpenMailerPrefs:
  1164.             DoMailerPreferencesDialog();
  1165.             break;
  1166.         
  1167.         case cOpenMiscPrefs:
  1168.             DoMiscPreferencesDialog();
  1169.             break;
  1170.  
  1171.         case cForgetPassword:
  1172.             InvalidateCurrentPassword();
  1173.             break;
  1174.  
  1175.         case cSysBug:
  1176.             ProgramBreak("SysBug");
  1177.             break;
  1178.             
  1179.         case cMacsBug:
  1180.             DebugStr("MenuMacsBug");
  1181.             break;
  1182.             
  1183.         case cTest1: Test1(); break;
  1184.         case cTest2: Test2(); break;
  1185.         case cTest3: Test3(); break;
  1186.         case cTest4: Test4(); break;
  1187.         
  1188.         case cDumpPrefs:
  1189.             gPrefs->DumpPrefs();
  1190.             break;
  1191.             
  1192.         case cDebugDumpThreads:
  1193.             DumpDebugThreadDescription();
  1194.             break;
  1195.  
  1196.         case cShowViewInspector:
  1197.             {
  1198.                 FailNIL(aWindow = gViewServer->NewTemplateWindow(kViewInspector, NULL));
  1199.                 aWindow->SetResizeLimits(CPoint(210,180),CPoint(210,1000));
  1200.                 aWindow->Open();
  1201.             }
  1202.             break;
  1203.         
  1204.         case cShowTargetInspector:
  1205.             {
  1206.                 FailNIL(aWindow = gViewServer->NewTemplateWindow(kTargetInspector, NULL));
  1207.                 aWindow->SetResizeLimits(CPoint(210,180),CPoint(210,1000));
  1208.                 aWindow->Open();
  1209.             }
  1210.             break;
  1211.  
  1212.         case cToggleFlushVolumes:
  1213.             fFlushVolumes = !fFlushVolumes;
  1214.             break;
  1215.         
  1216.         case cMenuForcedFatalError:
  1217.             PanicExitToShell("  Forced from menu");
  1218.             break;
  1219.             
  1220.         default:
  1221.             inherited::DoMenuCommand(aCommandNumber);
  1222.     }
  1223. }
  1224.  
  1225. pascal void TNewsAppl::DoSetupMenus()
  1226. {
  1227. // Test menu
  1228.     Enable(cTest1, true);
  1229.     Enable(cTest2, true);
  1230.     Enable(cTest3, true);
  1231.     Enable(cTest4, true);
  1232.     if (gPrefs)
  1233.         Enable(cDumpPrefs, true);
  1234.     Enable(cDebugDumpThreads, true);
  1235.     Enable(cShowViewInspector, true);
  1236.     Enable(cShowTargetInspector, true);
  1237.     EnableCheck(cToggleFlushVolumes, true, fFlushVolumes);
  1238.     Enable(cMacsBug, true);
  1239.     Enable(cSysBug, true);
  1240.     Enable(cMenuForcedFatalError, true);
  1241.     if (!gPrefs || !fApplIsRunning || !fGroupTreeDoc)
  1242.     {
  1243.         inherited::DoSetupMenus();
  1244.         Enable(cNew, false);
  1245.         if (gPrefs)
  1246.         {
  1247.             Enable(cOpen, false);
  1248.             // may not disable cOpen before we open the prefs,
  1249.             // as we need to be able to open it!
  1250.         }
  1251.         return;
  1252.     }
  1253.     Boolean lowSpace = MemSpaceIsLow();
  1254.  
  1255. // File menu
  1256.     Enable(cGroupListsMenu, !lowSpace);
  1257.     UpdateGroupListMenu();
  1258.  
  1259.     Enable(cNewGroupListDoc, !lowSpace);
  1260.     Enable(cOpenListOfAllGroups, !lowSpace);
  1261.  
  1262. // Discussions
  1263.     Enable(cDiscussionsPrefs, true);
  1264.     DiscussionShowType discShowType = DiscussionShowType(gPrefs->GetShortPrefs('disS'));
  1265.     EnableCheck(cPrefShowAllDiscussions, true, discShowType == kShowAllDiscs);
  1266.     EnableCheck(cPrefShowOnlyTodayDiscussions, true, discShowType == kShowTodaysDiscs);
  1267.     EnableCheck(cPrefShowDiscsWithUnreadArticles, true, discShowType == kShowDiscsWithUnreadArticles);
  1268.     EnableCheck(cPrefShowDiscsWithNewArticles, true, discShowType == kShowDiscsWithNewArticles);
  1269.  
  1270. // Articles
  1271.     Enable(cArticlesPrefs, true);
  1272.     ArticleShowType showWhat = ArticleShowType(gPrefs->GetShortPrefs('artS'));
  1273.     EnableCheck(cPrefShowAllArticles, true, showWhat == kShowAllArticles);
  1274.     EnableCheck(cPrefShowOnlyFirstArticle, true, showWhat == kShowFirstArticleOnly);
  1275.     EnableCheck(cPrefShowOnlyUnreadArticles, true, showWhat == kShowUnreadArticles);
  1276.     EnableCheck(cPrefShowOnlyNewArticles, true, showWhat == kShowNewArticles);
  1277.     EnableCheck(cPrefShowNoneArticles, true, showWhat == kShowNoArticles);
  1278.  
  1279. // Preferences
  1280.     if (!lowSpace)
  1281.     {
  1282.         Enable(cFontNameMenu, true);
  1283.         Enable(cFontSizeMenu, true);
  1284.         Enable(cOpenYourNamePrefs, true);
  1285.         Enable(cOpenBinariesPrefs, true);
  1286.         Enable(cOpenEditorPrefs, true);
  1287.         Enable(cOpenMailerPrefs, true);
  1288.         Enable(cOpenNewsServerPrefs, true);
  1289.         Enable(cOpenMiscPrefs, true);
  1290.         Enable(cUpdateGroupTree, true);
  1291.         Enable(cRebuildGroupTree, true);
  1292.         Enable(cForgetPassword, HasPassword());
  1293.     }
  1294.     
  1295. // Windows
  1296.     DoWindowsMenu(-1);
  1297.  
  1298. // inherited
  1299.     inherited::DoSetupMenus();
  1300.     
  1301.     if (IsControlKeyDown())
  1302.         Enable(cQuit, true);
  1303. }
  1304.